package com.wolfsea.launcherdemo
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.util.Log
import android.view.*
import androidx.core.view.get
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope

/**
 *@desc LauncherLayout
 *@author liuliheng
 *@time 2022/12/16  0:17
 **/
class LauncherLayout @JvmOverloads constructor(
    context: Context,
    attributeSet: AttributeSet? = null
) : ViewGroup(context, attributeSet), CoroutineScope by MainScope() {

    private val circlesDistance = context.resources.getDimension(R.dimen.dp_5)
    private val horizontalSpace = context.resources.getDimension(R.dimen.dp_20).toInt()

    private var downX = 0
    private var flagDownX = 0
    private var downY = 0
    private var totalMovedX = 0
    //lastTotalMovedX确保移动的距离为width的整数倍
    private var lastTotalMovedX = 0
    private var calcTotalMovedX = 0

    private var pageCount = 0
    private var currentPage = 0

    private val selectedPaint by lazy {
        Paint().apply {
            isAntiAlias = true
            isDither = true
            style = Paint.Style.FILL
            strokeWidth = context.resources.getDimension(R.dimen.dp_1)
            color = context.resources.getColor(R.color.purple_200)
        }
    }

    private val unSelectedPaint by lazy {
        Paint().apply {
            isAntiAlias = true
            isDither = true
            style = Paint.Style.FILL
            strokeWidth = context.resources.getDimension(R.dimen.dp_1)
            color = context.resources.getColor(R.color.purple_500)
        }
    }

    private val launcherItemMap by lazy {
        mutableMapOf<Int, LauncherItemLayout>()
    }

    init {
        setBackgroundColor(context.resources.getColor(R.color.color_e3dede))
    }

    override fun onFinishInflate() {
        super.onFinishInflate()

        val contentDataList = mutableListOf<ContentData>()

        val dataArray = arrayOf(
            "统信软件",
            "鲲鹏",
            "创新中心",
            "工具",
            "应用范围",
            "递归",
            "嵌套",
            "进程",
            "性能",
            "最大限度",
            "循环",
            "汇编代码",
            "重要",
            "事实上",
            "编写",
            "六个月",
            "优惠券",
            "安装",
            "鲜明对比",
            "应用商店",
            "调查",
            "芯片",
            "可能",
            "消息",
            "相关人士",
            "关系部门",
            "投资人",
            "暴雪",
            "解决方案",
            "发布",
            "是编程中",
            "重要",
            "概念",
            "高级语言",
            "得到",
            "广泛",
            "应用",
            "硬件层",
            "实现",
            "重要性",
            "不言而喻",
            "但是",
            "现代编程",
            "许多",
            "语言",
            "完全可以",
            "使用循环",
            "我们",
            "利用",
            "函数",
            "映射",
            "解析式",
            "实现",
            "相同",
            "功能",
            "但是",
            "情况下",
            "关键字",
            "关键字",
            "跳过",
            "元素",
            "加快",
            "目前",
            "可用模型",
            "还不够好",
            "不足以",
            "生命科学",
            "领域",
            "重大影响",
            "科学家",
            "都说",
            "只能",
            "只能",
            "情况下",
            "发挥些许",
            "作用",
            "基因组",
            "前景的",
            "应用方向",
            "尚属",
            "起步阶段",
            "看好",
        )

        for (item in dataArray) {
            contentDataList.add(ContentData(R.drawable.ic_launcher00, item))
        }

        pageCount = if (dataArray.size % BaseConstant.ITEMS_PER_PAGE == 0) {
            dataArray.size / BaseConstant.ITEMS_PER_PAGE
        } else {
            dataArray.size / BaseConstant.ITEMS_PER_PAGE + 1
        }

        for (i in 0.until(pageCount)) {
            val itemList = contentDataList.subList(
                i * BaseConstant.ITEMS_PER_PAGE,
                Math.min(contentDataList.size, (i + 1) * BaseConstant.ITEMS_PER_PAGE)
            )
            addContent(itemList, i)
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        for (i in 0.until(childCount)) {
            val child = get(i)
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0)
        }

        setMeasuredDimension(
            MeasureSpec.getSize(widthMeasureSpec) - paddingStart - paddingEnd,
            MeasureSpec.getSize(heightMeasureSpec) - paddingTop - paddingBottom
        )
    }

    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        for (i in 0.until(childCount)) {
            val child = get(i)
            val childMeasuredWidth = child.measuredWidth
            val childMeasuredHeight = child.measuredHeight

            val cl = childMeasuredWidth * i
            val ct = 0
            val cr = cl + childMeasuredWidth
            val cb = childMeasuredHeight

            child.layout(
                cl,
                ct,
                cr,
                cb
            )
        }
    }

    override fun dispatchDraw(canvas: Canvas?) {
        super.dispatchDraw(canvas)
        if (pageCount > 1) {
            val cy = this.measuredHeight.toFloat() * 4 / 5

            /*
             * 圆形指示器
             * */
            for (i in 0.until(pageCount)) {
                canvas?.drawCircle(
                    calculatePointIndicatorX(i),
                    cy,
                    circlesDistance,
                    if (currentPage == i) selectedPaint else unSelectedPaint
                )
            }

            /*
             * 圆形指示器逐渐滚动效果
             * */
            for (i in 0.until(pageCount)) {
                if (currentPage == i) {
                    canvas?.drawCircle(
                        calculatePointIndicatorX(i) - (calcTotalMovedX / (horizontalSpace / 4F)),
                        cy,
                        circlesDistance,
                        selectedPaint
                    )
                }
            }
        }
    }

    override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
        when (ev?.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.d(TAG,"onInterceptTouchEvent---MotionEvent.ACTION_DOWN")
                flagDownX = ev.x.toInt()
                downX = flagDownX
                downY = ev.y.toInt()
            }
            MotionEvent.ACTION_MOVE -> {
                Log.d(TAG,"onInterceptTouchEvent---MotionEvent.ACTION_MOVE")
                val actionMoveX = ev.x.toInt()
                if (Math.abs(actionMoveX - downX) >= BaseConstant.MIN_SLIDE_DISTANCE && !itemInDragging()) {
                    downX = actionMoveX
                    return true
                }
            }
        }
        return super.onInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        performClick()
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {
                flagDownX = event.x.toInt()
                downX = flagDownX
                downY = event.y.toInt()
                Log.d(
                    TAG,
                    "ACTION_DOWN ---> downX:${downX},downY:${downY}"
                )
            }
            MotionEvent.ACTION_MOVE -> {
                actionMovePageSwitch(event)
            }
            MotionEvent.ACTION_CANCEL -> {
                totalMovedX = lastTotalMovedX
                scrollTo(-totalMovedX, 0)
            }
            MotionEvent.ACTION_UP -> {
                actionUpPageSwitch(event)
            }
        }
        return true
    }

    override fun generateLayoutParams(attrs: AttributeSet?): LayoutParams {
        return MarginLayoutParams(context, attrs)
    }

    override fun performClick(): Boolean {
        return super.performClick()
    }

    private fun actionMovePageSwitch(event: MotionEvent) {
        val actionMovedX = event.x.toInt()
        val actionMovedY = event.y.toInt()
        val diffMovedX = actionMovedX - downX
        val diffMovedY = actionMovedY - downY
        Log.d(
            TAG,
            "ACTION_MOVE ---> diffMovedX:${diffMovedX},diffMovedY:${diffMovedY}"
        )
        if (Math.abs(diffMovedX) > Math.abs(diffMovedY)) {
            totalMovedX += diffMovedX
            calcTotalMovedX += diffMovedX
            totalMovedX = if (diffMovedX < 0) {
                //左滑
                Math.max(totalMovedX, -(pageCount - 1) * width)
            } else {
                //右滑
                Math.min(0, totalMovedX)
            }
            Log.d(TAG, "ACTION_MOVE ---> totalMovedX:${totalMovedX}")
            scrollTo(-totalMovedX, 0)
        }
        downX = actionMovedX
        downY = actionMovedY
    }

    private fun actionUpPageSwitch(event: MotionEvent) {
        val actionUpDiffValueX = event.x.toInt() - flagDownX
        if (actionUpDiffValueX < 0) {
            //左滑
            val modMovedValue = Math.abs(calcTotalMovedX % width)
            totalMovedX = if (modMovedValue > BaseConstant.MIN_MOVED_DISTANCE) {
                Log.d(
                    TAG,
                    "ACTION_UP-->currentPage-->${currentPage},than MIN_MOVED_DISTANCE left slide"
                )
                currentPage++
                Math.max(lastTotalMovedX - width, -(pageCount - 1) * width)
            } else {
                Log.d(
                    TAG,
                    "ACTION_UP-->currentPage-->${currentPage},less MIN_MOVED_DISTANCE left slide"
                )
                Math.max(lastTotalMovedX, -(pageCount - 1) * width)
            }
        } else {
            //右滑
            val modMovedValue = Math.abs(calcTotalMovedX % width)
            totalMovedX = if (modMovedValue > BaseConstant.MIN_MOVED_DISTANCE) {
                Log.d(
                    TAG,
                    "ACTION_UP-->currentPage-->${currentPage},than MIN_MOVED_DISTANCE right slide"
                )
                currentPage--
                Math.min(0, lastTotalMovedX + width)
            } else {
                Log.d(
                    TAG,
                    "ACTION_UP-->currentPage-->${currentPage},less MIN_MOVED_DISTANCE right slide"
                )
                Math.min(0, lastTotalMovedX)
            }
        }
        currentPage = Math.max(0, Math.min(currentPage, pageCount - 1))
        lastTotalMovedX = totalMovedX
        scrollTo(-totalMovedX, 0)
        calcTotalMovedX = 0
    }

    private fun addContent(contentDataSet: MutableList<ContentData>, pageIndex: Int) {
        val layout = LayoutInflater.from(context).inflate(R.layout.layout_item_content, this, false)
        val llContent = layout.findViewById<LauncherItemLayout>(R.id.layout_content_item)
        launcherItemMap[pageIndex] = llContent
        for (i in contentDataSet.indices) {
            val contentData = contentDataSet[i]
            llContent.addContent(contentData, i)
        }

        addView(
            layout,
            MarginLayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT
            )
        )
    }

    /*计算圆形指示器的x轴坐标*/
    private fun calculatePointIndicatorX(pageIndex: Int): Float {
        return if (pageCount % 2 == 0) {
            val middleValue = pageCount / 2
            val space = when {
                pageIndex == middleValue - 1 -> {
                    -horizontalSpace / 2
                }
                pageIndex == middleValue -> {
                    horizontalSpace / 2
                }
                pageIndex < middleValue - 1 -> {
                    (pageIndex - (middleValue - 1)) * horizontalSpace - horizontalSpace / 2
                }
                pageIndex > middleValue -> {
                    (pageIndex - middleValue) * horizontalSpace + horizontalSpace / 2
                }
                else -> {
                    0
                }
            }
            width.toFloat() / 2 + space - totalMovedX
        } else {
            width.toFloat() / 2 + (pageIndex - pageCount / 2) * horizontalSpace - totalMovedX
        }
    }

    fun getCurrentPage(): Int = currentPage

    fun itemInDragging(): Boolean = launcherItemMap[currentPage]?.launcherItemDragging() ?: false

    companion object {
        const val TAG = "LauncherLayout"
    }

}